package cc.rengu.igas.channel.cups.core.service.base;

import cc.rengu.igas.channel.cups.common.constant.CupsParamConstant;
import cc.rengu.igas.channel.cups.common.constant.CupsTreeNodeConstant;
import cc.rengu.igas.channel.cups.common.enums.RespCodeEnum;
import cc.rengu.igas.channel.cups.core.model.CupsFieldRspBean;
import cc.rengu.igas.channel.cups.core.realize.CupsMacService;
import cc.rengu.igas.channel.cups.core.realize.impl.CupsMacServiceImpl;
import cc.rengu.igas.channel.cups.facade.base.BaseRequest;
import cc.rengu.igas.channel.cups.facade.bean.CupsTermInfo;
import cc.rengu.igas.share.facade.bean.CupsFieldBean;
import cc.rengu.igas.share.facade.bean.cups.F39_RspCodeEnum;
import cc.rengu.jradp.mods.trmsg.iso8583.MacUtil;
import cc.rengu.jradp.schedule.ScheduleImpl;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.DstChannelInfoMapper;
import cc.rengu.oltp.service.common.dao.DstTxnAuthCfgMapper;
import cc.rengu.oltp.service.common.dao.impl.DstChannelInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.DstTxnAuthCfgMapperImpl;
import cc.rengu.oltp.service.common.entity.DstChannelInfo;
import cc.rengu.oltp.service.common.entity.DstTxnAuthCfg;
import cc.rengu.oltp.service.common.entity.KeyInfo;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.cache.UnifiedCache;
import com.alibaba.fastjson.JSON;

import java.io.UnsupportedEncodingException;

/**
 * 冲正类业务处理基类
 *
 * @author who
 */
@SuppressWarnings("rawtypes")
public abstract class BaseACService<T> extends RadpService {
    /**
     * 对称密钥 3DES算法，国际
     */
    protected static final String DES3 = "3DES";
    /**
     * 对称密钥 SM4算法。国密
     */
    protected static final String SM4 = "SM4";

    @Override
    protected int bizInit(String s) {
        return 0;
    }

    /**
     * 通道、交易权限权限
     *
     * @throws Exception 业务处理异常
     */
    protected void channelPermissionCheck() throws Exception {
        BaseRequest baseRequest = new BaseRequest();
        ConvertUtil.convertOutput(baseRequest);
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String instId = baseRequest.getHeader().getInstId();
        instId = StringUtil.isEmptyOrNull(instId) ? AppParamConstant.DEFAULT_INSTID : instId;
        String txnNum = getCupsTxnNum(baseRequest);
        /* 通道状态检查 */
//        String dstChannelKey = "CHANNEL_INFO_CACHE" +":"+"ISS" + ":" + instId + ChannelEnum.CUPS.getChannelType();
//        rglog.debug("dstChannelKey<{}-{}>",dstChannelKey);
//        DstChannelInfo dstChannelInfo = JSON.parseObject(RedisUtil.onceGet(dstChannelKey), DstChannelInfo.class);
//        if (null == dstChannelInfo || !AppParamConstant.YES.equals(dstChannelInfo.getDstChannelStatus().toUpperCase(Locale.ENGLISH))) {
//            rglog.error("支付渠道<{}-{}>未配置或已停用！", ChannelEnum.CUPS.getChannelType(), (null == dstChannelInfo) ? "" : dstChannelInfo.getDstChannelName());
//            throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
//        }

        String dstChannelKey = instId + ChannelEnum.CUPS.getChannelType();
        DstChannelInfo dstChannelInfo = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelKey), DstChannelInfo.class);
        if (null == dstChannelInfo) {
            DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
            dstChannelInfo = dstChannelInfoMapper.selectDstChannelInfoByPrimaryKey(instId, ChannelEnum.CUPS.getChannelType());
        }
        if (null == dstChannelInfo || !dstChannelInfo.getDstChannelStatus().equalsIgnoreCase(AppParamConstant.YES)) {
            rglog.error("支付渠道<{}-{}>未配置或已停用！", ChannelEnum.CUPS.getChannelType(), (null == dstChannelInfo) ? "" : dstChannelInfo.getDstChannelName());
            throw new BizException(OltpRpcdEnum.CHANNEL_DISABLED);
        }

        xmlTreeUtil.setXmlTreeObjectValue(CupsTreeNodeConstant.DST_CHANNEL_INFO, dstChannelInfo);
        String channelId = ChannelEnum.CUPS.getChannelType();
        String dstChannelAuthKey = instId.trim() + channelId.trim() + txnNum.trim();
        DstTxnAuthCfg dstTxnAuthCfg = JSON.parseObject(RedisUtil.hashGet(AppParamConstant.CHANNEL_TXN_CACHE, dstChannelAuthKey), DstTxnAuthCfg.class);
        if (null == dstTxnAuthCfg) {
            DstTxnAuthCfgMapper dstTxnAuthCfgMapper = new DstTxnAuthCfgMapperImpl();
            dstTxnAuthCfg = dstTxnAuthCfgMapper.selectDstTxnAuthCfgByPrimaryKey(instId, channelId, txnNum);
        }
        if (null == dstTxnAuthCfg || !dstTxnAuthCfg.getSupportFlag().equalsIgnoreCase(AppParamConstant.YES)) {
            rglog.error("支付通道<{}-{}>不支持此交易，通道交易码:<{}>", dstChannelInfo.getDstChannelId(), dstChannelInfo.getDstChannelName(), txnNum);
            throw new BizException(OltpRpcdEnum.TRANS_NOT_SUPPORT);
        }
        if (dstTxnAuthCfg.getMsgRegisterFlag() != null && dstTxnAuthCfg.getMsgRegisterFlag().isEmpty()) {
            xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.MSG_REG_FLAG, dstTxnAuthCfg.getMsgRegisterFlag());
        }
    }

    /**
     * 获取银联清算日期
     *
     * @param settleDate 交易日期
     * @return 银联清算日期
     */
    protected String getCupsSettleDate(String settleDate) {
        if (settleDate.length() != 4) {
            return settleDate;
        }
        String yearSettleDate = DateUtil.getCurrentDate();
        String year = yearSettleDate.substring(0, 4);
        String month = yearSettleDate.substring(4, 6);
        String settleMonth = settleDate.substring(0, 2);
        if ("01".equals(settleMonth) && "12".equals(month)) {
            return String.format("%d", Integer.parseInt(year) + 1) + settleDate;
        } else if ("12".equals(settleMonth) && "01".equals(month)) {

            return String.format("%d", Integer.parseInt(year) - 1) + settleDate;
        }
        return year + settleDate;
    }

    /**
     * 获取银联配置交易码
     * 1.优先取BaseRequest的Header里的TxnNum
     * 2.其次取cupsField的 F0+F3前两位+F25
     *
     * @param baseRequest
     * @return
     * @throws Exception
     */
    protected static String getCupsTxnNum(BaseRequest baseRequest) throws Exception {
        //  报文头中的交易码
        if (!StringUtil.isEmptyOrNull(baseRequest.getHeader().getTxnNum())) {
            return baseRequest.getHeader().getTxnNum();
        }

        //  默认交易码
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        String msgType = xmlTreeUtil.getXmlTreeStringValue("msgType");
        String procCode = xmlTreeUtil.getXmlTreeStringValue("procCode");
        String conCode = xmlTreeUtil.getXmlTreeStringValue("conCode");
        String txnNum = msgType + procCode.substring(0, 2) + conCode;
        baseRequest.getHeader().setTxnNum(txnNum);
        ConvertUtil.convertInput(baseRequest);
        return txnNum;
    }

    protected CupsFieldRspBean callCups(CupsFieldBean cupsFieldBean) throws Exception {
        String cupsTxnNum = cupsFieldBean.getCupsField().getMsgType() + cupsFieldBean.getCupsField().getProcCode().substring(0, 2)
                + cupsFieldBean.getCupsField().getConCode();
        return callCups(cupsFieldBean, cupsTxnNum);
    }

    protected CupsFieldRspBean callCups(CupsFieldBean cupsFieldBean, String cupsTxnNum) throws Exception {
        return callCups(cupsFieldBean, cupsTxnNum, CupsParamConstant.CUPS_8583_MAC_TYPE_COMMON);
    }

    protected CupsFieldRspBean callCups(CupsFieldBean cupsFieldBean, String cupsTxnNum, String macType) throws Exception {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        int iReturnCode = 0;
        //  请求 (内部树)
        ConvertUtil.convertInput(cupsFieldBean);
        /*计算macblock*/
        MacUtil commonMac = null;
        if (!StringUtil.isEmptyOrNull(macType)) {
            if (!StringUtil.isEmptyOrNull(cupsFieldBean.getCupsField().getOrigData())) {
                xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_MACBLOCK_ORIG_DATA_ELEMTS, cupsFieldBean.getCupsField().getOrigData().substring(0, 20));
            }
            commonMac = (MacUtil) UnifiedCache.get(CupsParamConstant.CUPS_8583_MAC_CACHE_NAME,
                    CupsParamConstant.CUPS_8583_MAC_FILE + macType);
            byte[] macBlock = commonMac.genMacBlock(macType);
            if (macBlock == null) {
                throw new BizException(RespCodeEnum.GENERATE_MAC_BLOCK_ERROR.getRespCode(), RespCodeEnum.GENERATE_MAC_BLOCK_ERROR.getRespDesc());
            }
            xmlTreeUtil.setXmlTreeStringValue(CupsTreeNodeConstant.CUPS_MAC_BLOCK, new String(macBlock, CupsParamConstant.GB18030));
        }
        xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TXN_NUM, cupsTxnNum);
        DstChannelInfo dstChannelInfo = (DstChannelInfo) xmlTreeUtil.getXmlTreeObjectValue(CupsTreeNodeConstant.DST_CHANNEL_INFO, DstChannelInfo.class);
        iReturnCode = schedule.callService(dstChannelInfo.getDstServiceName(), 0);
        //通讯层判断
        if (ScheduleImpl.SERVICE_TIMEOUT == iReturnCode) {
            rglog.error("调用银联cups服务<{}>超时，iReturnCode:<{}>", dstChannelInfo.getDstServiceName(), iReturnCode);
            throw new BizException(OltpRpcdEnum.BIZ_PROCESS_TIMEOUT.getRespCode(), OltpRpcdEnum.BIZ_PROCESS_TIMEOUT.getRespDesc());
        } else if (ScheduleImpl.SERVICE_SUCCESS != iReturnCode) {
            rglog.error("调用银联cups服务<{}>失败，iReturnCode:<{}>", dstChannelInfo.getDstServiceName(), iReturnCode);
            throw new BizException(OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespCode(), OltpRpcdEnum.CALL_BIZ_SERVICE_ERROR.getRespDesc());
        } else if (F39_RspCodeEnum._98.getCode().equals(xmlTreeUtil.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_RSP_CODE))) {
            rglog.error("银联cups服务<{}>应答超时，respCode:<{}>", dstChannelInfo.getDstServiceName(), xmlTreeUtil.getXmlTreeStringValue(CupsTreeNodeConstant.CUPS_RSP_RSP_CODE));
            throw new BizException(OltpRpcdEnum.BIZ_PROCESS_TIMEOUT.getRespCode(), OltpRpcdEnum.BIZ_PROCESS_TIMEOUT.getRespDesc());
        }

        //  清缓存流水
        String tunlSsn = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.CHANNEL_SEQ_NUM);
        UnifiedCache.remove(CupsParamConstant.CACHE_CUPS_SN, tunlSsn);

        // 获取应答
        CupsFieldRspBean cupsFieldRspBean = new CupsFieldRspBean();
        ConvertUtil.convertOutput(cupsFieldRspBean);
        /* 生成应答macBlock, 验MAC */
        if (!StringUtil.isEmptyOrNull(macType)) {
            String mac = cupsFieldRspBean.getCupsFieldRsp().getMac();
            byte[] macBlockRsp = commonMac.getMacBlock(macType);
            CupsMacService cupsMacService = new CupsMacServiceImpl();
            KeyInfo keyInfo = (KeyInfo) xmlTreeUtil.getXmlTreeObjectValue(CupsTreeNodeConstant.CUPS_MAC_KEY_INFO, KeyInfo.class);
            boolean flag = cupsMacService.verifyMacString(keyInfo, mac, new String(macBlockRsp, CupsParamConstant.GB18030));
            if (!flag) {
                rglog.error("验证mac失败");
                throw new BizException(RespCodeEnum.VERIFY_MAC_ERROR.getRespCode(), RespCodeEnum.VERIFY_MAC_ERROR.getRespDesc());
            }
        }
        return cupsFieldRspBean;
    }

    /**
     * 银联104域-PI用法
     *
     * @param cupsTermInfo 终端信息
     * @return 104域信息
     */
    protected String packF104Pi(CupsTermInfo cupsTermInfo) throws UnsupportedEncodingException {

        if (cupsTermInfo == null) {
            return null;
        }
        StringBuilder buf = new StringBuilder();
        if (cupsTermInfo.getLongitude() != null) {
            buf.append("01");
            //buf.append(String.format("%03d", cupsTermInfo.getLongitude().length()));
            buf.append(Integer.toHexString(cupsTermInfo.getLongitude().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getLongitude().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getLongitude().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getLongitude().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getLatitude() != null) {
            buf.append("02");
            //buf.append(String.format("%03d", cupsTermInfo.getLatitude().length()));
            buf.append(Integer.toHexString(cupsTermInfo.getLatitude().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getLatitude().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getLatitude().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getLatitude().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getNetworkLicense() != null) {
            buf.append("03");
            buf.append("05");
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getNetworkLicense().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getDeviceType() != null) {
            buf.append("04");
            buf.append("02");
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getDeviceType().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getSerialNum() != null) {
            buf.append("05");
            buf.append(Integer.toHexString(cupsTermInfo.getSerialNum().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getSerialNum().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getSerialNum().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getSerialNum().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getEncryptRandNum() != null) {
            buf.append("06");
            buf.append(Integer.toHexString(cupsTermInfo.getEncryptRandNum().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getEncryptRandNum().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getEncryptRandNum().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getEncryptRandNum().getBytes(CupsParamConstant.GB18030)));
        }
        if (cupsTermInfo.getSecretText() != null) {
            buf.append("07");
            buf.append("08");
            //base64值转为hex
            buf.append(StringUtil.binaryToHexString(StringUtil.base64StringToBinary(cupsTermInfo.getSecretText())));
        }
        if (cupsTermInfo.getAppVersion() != null) {
            buf.append("08");
            buf.append(Integer.toHexString(cupsTermInfo.getAppVersion().length()).length() == 1
                    ? "0" + Integer.toHexString(cupsTermInfo.getAppVersion().length()).toUpperCase() : Integer.toHexString(cupsTermInfo.getAppVersion().length()).toUpperCase());
            buf.append(StringUtil.binaryToHexString(cupsTermInfo.getAppVersion().getBytes(CupsParamConstant.GB18030)));
        }
        String f104Field = ("PI" + String.format("%03d", buf.toString().length() / 2));
        return StringUtil.binaryToHexString(f104Field.getBytes(CupsParamConstant.GB18030)) + buf.toString();
    }

}
